//***********************************************************************************************//
/// \file     uclog.h
/// \version  0.1.0
/// \brief    UCLOG is the library that provides macros for easy log output.
/// \author   Krystian Rebas
/// \details  Sorry, no user manual, learn from the code ;p
///           For more details about UCLOG usage see uclog.c/cfg files.
/// \note     Copyright (C) 2012 by Krystian Rebas.
///           All rights reserved.
///
///           Redistribution and use in source and binary forms, with or without
///           modification, are permitted provided that the following conditions are met: 
///           
///           1. Redistributions of source code must retain the above copyright notice, this
///           list of conditions and the following disclaimer. 
///           2. Redistributions in binary form must reproduce the above copyright notice,
///           this list of conditions and the following disclaimer in the documentation
///           and/or other materials provided with the distribution. 
///
///           THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
///           ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
///           WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
///           DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
///           ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
///           (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
///           LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
///           ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
///           (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
///           SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
///
//***********************************************************************************************//
#ifndef UCLOG_H
#define UCLOG_H

//***********************************************************************************************//
//* doxygen data ///////////////////////////////////////////////////////////////// doxygen data *//
//***********************************************************************************************//

/// \addtogroup UCLOG uclog
/// @{

//***********************************************************************************************//
//* defines, macros /////////////////////////////////////////////////////////// defines, macros *//
//***********************************************************************************************//

// Defines used by LOG configuration file  ////////////////////////////////////////////////////////

/// value for UCLOG_MODE: use printf/stdout for log output
#define USE_STDOUT                0

/// value for UCLOG_MODE: use memory buffer for log output (useful for cases where stdout 
/// is unavailable)
#define USE_MEM_BUFFER            1

// Include LOG configuration file //////////////////////////////////////////////////////////////////

// Configuration file path can be defined in application as UCLOG_CFG_FILE or assumed as "uclog.cfg" if not defined.
// This trick allows use separate config files for differend modules, what may be sometimes useful :)

#ifndef UCLOG_CFG_FILE
  #define UCLOG_CFG_FILE            "uclog.cfg"
#endif

#include UCLOG_CFG_FILE

//-----------------------------------------------------------------------------------------------//
#if (UCLOG_ENABLED)
//-----------------------------------------------------------------------------------------------//

// Checks if all config parameters are defined properly ///////////////////////////////////////////

#ifndef UCLOG_MODE
  #warning UCLOG_MODE not defined - using defaults, check your UCLOG_CFG_FILE file!
  #define UCLOG_MODE USE_STDOUT
#endif

#if (UCLOG_MODE == USE_STDOUT)
//  nothing to check actually...
#elif UCLOG_MODE == USE_MEM_BUFFER
#define UCLOG_BUFFER                UCLOG_MemBuffer
  extern char UCLOG_BUFFER[UCLOG_BUFFER_SIZE];
#else
  #error UCLOG_MODE defined with unsupported value, check your UCLOG_CFG_FILE file!
#endif

#ifndef UCLOG_SEVERITY_LEVEL
  #warning UCLOG_SEVERITY_LEVEL not defined - using defaults, check your UCLOG_CFG_FILE file!

  #define UCLOG_SEVERITY_LEVEL      1
#endif

#ifndef UCLOG_USE_THREAD_SAFE_PRINT
  #warning UCLOG_USE_THREAD_SAFE_PRINT not defined - using defaults, check your UCLOG_CFG_FILE file!

  #define UCLOG_USE_THREAD_SAFE_PRINT 0
#endif

#ifndef UCLOG_VOID
  #warning UCLOG_VOID not defined - using defaults, check your UCLOG_CFG_FILE file!
  #define UCLOG_VOID                    void
#endif

#ifndef UCLOG_CHAR
  #warning UCLOG_CHAR not defined - using defaults, check your UCLOG_CFG_FILE file!
  #define UCLOG_CHAR                    char
#endif

#ifndef UCLOG_ULONG
  #warning UCLOG_ULONG not defined - using defaults, check your UCLOG_CFG_FILE file!
  #define UCLOG_ULONG                   unsigned long
#endif

//***********************************************************************************************//
//* exported function prototypes ///////////////////////////////// exported function prototypes *//
//***********************************************************************************************//

// log macro prototypes with regard to severity level ////////////////////////////////////////////

#if (UCLOG_SEVERITY_LEVEL == 0 ) // user-def
  //severities are defined by user
#elif (UCLOG_SEVERITY_LEVEL < 5) // FATAL

  #ifndef UCLOG_SEVERITY_FATAL
    #define UCLOG_SEVERITY_FATAL     ""
    #warning UCLOG_SEVERITY_FATAL not defined - using defaults, check your UCLOG_CFG_FILE file!
  #endif
#elif (UCLOG_SEVERITY_LEVEL < 4) // ERROR
  #ifndef UCLOG_SEVERITY_ERROR
    #define UCLOG_SEVERITY_ERROR     ""
    #warning UCLOG_SEVERITY_ERROR not defined - using defaults, check your UCLOG_CFG_FILE file!
  #endif
#elif (UCLOG_SEVERITY_LEVEL < 3) // WARNING
  #ifndef UCLOG_SEVERITY_WARNING
    #define UCLOG_SEVERITY_WARNING  ""
    #warning UCLOG_SEVERITY_WARNING not defined - using defaults, check your UCLOG_CFG_FILE file!
  #endif
#elif (UCLOG_SEVERITY_LEVEL < 2) // INFO
  #ifndef UCLOG_SEVERITY_INFO
    #define UCLOG_SEVERITY_INFO      ""
    #warning UCLOG_SEVERITY_INFO not defined - using defaults, check your UCLOG_CFG_FILE file!
  #endif
#endif


#ifdef UCLOG_SEVERITY_INFO
  extern UCLOG_VOID UCLOG_printInfo(char* fs, ...);
  #define LOG_INFO(a)             UCLOG_printInfo a
#endif

#ifdef UCLOG_SEVERITY_WARNING
  extern UCLOG_VOID UCLOG_printWarning(char* fs, ...);
  #define LOG_WARNING(a)          UCLOG_printWarning a
#endif

#ifdef UCLOG_SEVERITY_ERROR
  extern UCLOG_VOID UCLOG_printFatal(char* fs, ...);
  #define LOG_ERROR(a)            UCLOG_printError a
#endif

#ifdef UCLOG_SEVERITY_FATAL
  extern UCLOG_VOID UCLOG_printError(char* fs, ...);
  #define LOG_FATAL(a)            UCLOG_printFatal a
#endif

#ifdef UCLOG_SEVERITY_DEBUG
  extern UCLOG_VOID UCLOG_printDebug(char* fs, ...);
  #define LOG_DFATAL(a)            UCLOG_printFatal a
#endif

// basic common logger macro prototypes ///////////////////////////////////////////////////////////

/// Prints log output for given severity.
/// usage: LOG(<severity>, ("printf-like formatting string", <var>, <var>,...) )
#define LOG(severity, message)                 LOG_##severity (message)

/// Prints CR character (new line) to given severity.
/// usage: LOG(<severity>)
#define LOG_CR(severity)                 LOG_##severity (("\n"))

/// Prints log output to given severity if condition b is !0.
/// usage: LOG_IF(<severity>, ("printf-like formatting string", <condition>, <var>, <var>,...), condition )
#define LOG_IF(severity, message, condition)           if(condition) LOG(severity, message)


/// Prints log output to FATAL severity if condition b is !0.
/// usage: LOG_ASSERT(<severity>, ("printf-like formatting string", <condition>, <var>, <var>,...) )
#define LOG_ASSERT(message, condition)          LOG_IF(FATAL, message, condition)

#if (defined UCLOG_USE_DEBUG_MODE && defined DEBUG)
/// Maps debug mode LOG macros to LOG macros
  #define DLOG(severity, message)                       LOG(severity, message)
  #define DLOG_CR(severity)                             LOG_CR(severity)
  #define DLOG_IF(severity, message, condition)         LOG_IF(severity, message, condition)
  #define DLOG_ASSERT(message, condition)               LOG_ASSERT(message, condition)
#else
  #define DLOG(severity, message)
  #define DLOG_CR(severity)
  #define DLOG_IF(severity, message, condition)
  #define DLOG_ASSERT(message, condition)
#endif


//-----------------------------------------------------------------------------------------------//
#else //UCLOG_ENABLED == 0
//-----------------------------------------------------------------------------------------------//

//In case LOG is not enabled, remove LOG macros calls from your code
#define LOG(severity, message)
#define LOG_CR(severity)
#define LOG_IF(severity, message, condition)
#define LOG_ASSERT(message, condition)
#define LOG_DASSERT(message, condition)
//And clean up unused defines
#undef USE_STDOUT
#undef USE_MEM_BUFFER
#undef UCLOG_CFG_FILE

#endif //UCLOG_ENABLED

#endif //UCLOG_H
